package org.flowers.unbeaten.security;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.flowers.unbeaten.base.constant.Constants;
import org.flowers.unbeaten.exception.BusinessException;
import org.flowers.unbeaten.exception.code.BaseResponseCode;
import org.flowers.unbeaten.util.DataResult;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;


/**
 * @description 自定义过滤器
 * @author RyanWang
 * @date 2021-07-16 15:59:11
 * @version 1.0
 */
@Slf4j
public class MyAccessControlFilter extends AccessControlFilter {

    /**
     * 如果返回的是true 就流转到下一个链式调用
     * 返回false 就会流转到 onAccessDenied方法
     * @param servletRequest
     * @param servletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) {
        return false;
    }

    /**
     * 如果返回true 就会流转到下一个链式调用
     * false 就是不会流转到下一个链式调用
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        try {
            log.info("接口的请求方式:{}", request.getMethod());
            log.info("接口的请求地址:{}", request.getRequestURL());
            // 从header中获取token
            String token = request.getHeader(Constants.ACCESS_TOKEN);
            // 如果header中不存在token
            if (StringUtils.isEmpty(token)) {
                throw new BusinessException(BaseResponseCode.TOKEN_ERROR);
            }
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(token, token);
            getSubject(servletRequest, servletResponse).login(usernamePasswordToken);
        } catch (BusinessException exception) {
            customResponse(exception.getMessageCode(), exception.getMessageDetail(), servletResponse);
            return false;
        } catch (AuthenticationException e) {
            if (e.getCause() instanceof BusinessException) {
                BusinessException exception = (BusinessException) e.getCause();
                customResponse(exception.getMessageCode(), exception.getMessageDetail(), servletResponse);
            } else {
                customResponse(BaseResponseCode.SYSTEM_BUSY.getCode(), BaseResponseCode.SYSTEM_BUSY.getMessage(), servletResponse);
            }
            return false;
        } catch (Exception e) {
            if (e.getCause() instanceof BusinessException) {
                BusinessException exception = (BusinessException) e.getCause();
                customResponse(exception.getMessageCode(), exception.getMessageDetail(), servletResponse);
            } else {
                customResponse(BaseResponseCode.SYSTEM_BUSY.getCode(), BaseResponseCode.SYSTEM_BUSY.getMessage(), servletResponse);
            }
            return false;
        }
        return true;
    }

    /**
     * 自定义响应前端
     * @param response
     * @param code
     * @param message
     */
    private void customResponse(Integer code, String message, ServletResponse response) {
        try {
            DataResult result = DataResult.getResult(code, message);
            response.setContentType("application/json; charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            String userJson = JSON.toJSONString(result);
            OutputStream out = response.getOutputStream();
            out.write(userJson.getBytes(StandardCharsets.UTF_8));
            out.flush();
        } catch (IOException e) {
            log.error("自定义响应前端错误: error={}", e);
        }
    }

}
